/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtspHeader.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"

CMkRtspTransport::CMkRtspTransport()
    : m_Transport("RTP")
    , m_Profile("AVP")   //Audio/Video profile
    , m_bUnicast(TRUE)
    , m_Layers(0)
    , m_RtpInterleaved(InvalidNum)
    , m_Ttl(0)
    , m_RtpPort(0)
    , m_ClientRtpPort(0)
    , m_ServerRtpPort(0)
    , m_Ssrc(0)
    , m_Mode("play")
    , m_RtcpInterleaved(1)
{

}

Uint32 CMkRtspTransport::ParseClientTransport(const MkString& Content)
{
    MkVector<MkString> VecParams;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, ";", VecParams);
    MkCheckErrorLog(ErrorCode, "split content:%s failed\n", Content.c_str());
    if (VecParams.empty()) {
        return InvalidParams;
    }
    MkVector<MkString>::iterator it = VecParams.begin();
    size_t nFind = it->find("TCP");
    m_LowerTransport = MkString::npos == nFind ? "UDP" : "TCP";
    it++;
    for (; it != VecParams.end(); it++) {
        ParseParamItem(*it);
    }
    return NoneError;
}

Uint32 CMkRtspTransport::ParseServerTransport(const MkString& Content)
{
    MkVector<MkString> VecParams;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, ";", VecParams);
    MkCheckErrorLog(ErrorCode, "split content:%s failed\n", Content.c_str());
    if (VecParams.empty()) {
        return InvalidParams;
    }
    MkVector<MkString>::iterator it = VecParams.begin();
    size_t nFind = it->find("TCP");
    m_LowerTransport = MkString::npos == nFind ? "UDP" : "TCP";
    it++;
    for (; it != VecParams.end(); it++) {
        ParseParamItem(*it);
    }
    return NoneError;
}

Uint32 CMkRtspTransport::ParseRtpInfo(const MkString& RtpInfo)
{
    MkVector<MkString> vecStr;
    Uint32 ErrorCode = CMkUtil::StringSplit(RtpInfo, ";", vecStr);
    MkCheckErrorLog(ErrorCode, "split rtp info:%s failed\n", RtpInfo.c_str());
    MkVector<MkString>::iterator it = vecStr.begin();
    size_t nFind = MkString::npos;
    for (; it != vecStr.end(); it++) {
        nFind = it->find(":");
        if (MkString::npos == nFind) {
            continue;
        }
        if ("seq" == it->substr(0, nFind)) {
            m_Seq = std::stoi(it->substr(nFind + 1));
        } else if ("rtptime" == it->substr(0, nFind)) {
            m_TimeStamp = std::stoi(it->substr(nFind + 1));
        }
    }
    return NoneError;
}

Uint32 CMkRtspTransport::ToClientTransportString(OUT MkString& Content) const
{
    Content = m_Transport + "/" + m_Profile;
    if (!m_LowerTransport.empty()) {
        Content += "/" + m_LowerTransport;
    }
    Content += ";" + m_bUnicast ? ";unicast" : ";multicast";
    if (!m_Destincation.empty()) {
        Content + ";destination=" + m_Destincation;
    }
    if (InvalidNum != m_RtpInterleaved) {
        Content += ";interleaved=" + std::to_string(m_RtpInterleaved) + "-" + std::to_string(m_RtpInterleaved + 1);
    }
    if (!m_Append.empty()) {
        Content += ";append=" + m_Append;
    }
    if (0 != m_Ttl) {
        Content += ";ttl=" + std::to_string(m_Ttl);
    }
    if (0 != m_Layers) {
        Content += ";layers=" + std::to_string(m_Layers);
    }
    if (0 != m_RtpPort) {
        Content += ";port=" + std::to_string(m_RtpPort) + "-" + std::to_string(m_RtpPort + 1);
    }
    if (0 != m_ClientRtpPort) {
        Content += ";client_port=" + std::to_string(m_ClientRtpPort) + "-" + std::to_string(m_ClientRtpPort + 1);
    }
    if (!m_Mode.empty()) {
        Content += ";mode=" + m_Mode;
    }
    return NoneError;
}

Uint32 CMkRtspTransport::ToServerTransportString(OUT MkString& Content) const
{
    Content = m_Transport + "/" + m_Profile;
    if (!m_LowerTransport.empty()) {
        Content += "/" + m_LowerTransport;
    }
    Content += ";" + m_bUnicast ? ";unicast" : ";multicast";
    if (!m_Destincation.empty()) {
        Content + ";destination=" + m_Destincation;
    }
    if (InvalidNum != m_RtpInterleaved) {
        Content += ";interleaved=" + std::to_string(m_RtpInterleaved) + "-" + std::to_string(m_RtcpInterleaved);
    }
    if (!m_Append.empty()) {
        Content += ";append=" + m_Append;
    }
    if (0 != m_Ttl) {
        Content += ";ttl=" + std::to_string(m_Ttl);
    }
    if (0 != m_Layers) {
        Content += ";layers=" + std::to_string(m_Layers);
    }
    if (0 != m_RtpPort) {
        Content += ";port=" + std::to_string(m_RtpPort) + "-" + std::to_string(m_RtpPort + 1);
    }
    if (0 != m_ClientRtpPort) {
        Content += ";client_port=" + std::to_string(m_ClientRtpPort) + "-" + std::to_string(m_ClientRtcpPort);
    }
    if (0 != m_ServerRtpPort) {
        Content += ";server_port=" + std::to_string(m_ServerRtpPort) + "-" + std::to_string(m_ServerRtcpPort);
    }
    if (0 != m_Ssrc) {
        MkString Tmp;
        Uint8 pbuf[Len16] = { 0 };
        pbuf[0] = (m_Ssrc >> 24) & 0xFF;
        pbuf[1] = (m_Ssrc >> 16) & 0xFF;
        pbuf[2] = (m_Ssrc >> 8) & 0xFF;
        pbuf[3] = m_Ssrc & 0xFF;
        CMkUtil::ByteToString(pbuf, 4, Tmp);
        Content += ";ssrc=" + Tmp;
    }
    if (!m_Mode.empty()) {
        Content += ";mode=\"" + m_Mode + "\"";
    }
    return NoneError;
}

Uint32 CMkRtspTransport::ParseParamItem(const MkString& Item)
{
    if ("unicast" == Item) {
        m_bUnicast = TRUE;
        return NoneError;
    }
    if ("multicast" == Item) {
        m_bUnicast = FALSE;
        return NoneError;
    }
    size_t nFind = Item.find("=");
    if (MkString::npos != nFind) {
        MkString Key = Item.substr(0, nFind);
        MkString Value = Item.substr(nFind + 1);
        if ("destination" == Key) {
            m_Destincation = Value;
        } else if ("interleaved" == Key) {
            nFind = Value.find("-");
            if (MkString::npos != nFind) {
                m_RtpInterleaved = std::stoi(Value.substr(0, nFind));
                m_RtcpInterleaved = std::stoi(Value.substr(nFind + 1));
            }
        } else if ("append" == Key) {
            m_Append = Value;
        } else if ("ttl" == Key) {
            m_Ttl = std::stoi(Value);
        } else if ("layers" == Key) {
            m_Layers = std::stoi(Value);
        } else if ("port" == Key) {
            nFind = Value.find("-");
            if (MkString::npos != nFind) {
                m_RtpPort = std::stoi(Value.substr(0, nFind));
            }
        } else if ("client_port" == Key) {
            nFind = Value.find("-");
            if (MkString::npos != nFind) {
                m_ClientRtpPort = std::stoi(Value.substr(0, nFind));
                m_ClientRtcpPort = std::stoi(Value.substr(nFind + 1));
            }
        } else if ("server_port" == Key) {
            nFind = Value.find("-");
            if (MkString::npos != nFind) {
                m_ServerRtpPort = std::stoi(Value.substr(0, nFind));
                m_ServerRtcpPort = std::stoi(Value.substr(nFind + 1));
            }
        } else if ("ssrc" == Key) {
            Uint8 pBuf[Len16] = { 0 };
            Uint32 nLen = 0;
            CMkUtil::StringToByte(Value, pBuf, nLen);
            m_Ssrc = pBuf[0] << 24 | pBuf[1] << 16 | pBuf[2] << 8 | pBuf[3];
        } else if ("mode" == Key) {
            m_Mode = Value;
        }
    }
    return NoneError;
}
